/**
 * 
 */
package de.fsujena.chat_pi.server.manager;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import de.fsujena.chat_pi.ressources.Room;
import de.fsujena.chat_pi.ressources.User;
import de.fsujena.chat_pi.ressources.message.SysMessage;
import de.fsujena.chat_pi.ressources.message.SysMessage.CATEGORY;
import de.fsujena.chat_pi.ressources.message.SysMessage.MESSAGE;
import de.fsujena.chat_pi.server.Server;
import de.fsujena.chat_pi.server.userInterface.GraphicalUI;

/**
 * @author Erik Hebestreit
 *
 */
public class RoomManager {
	public HashMap<String,Room> rooms = new HashMap<String,Room>();
	public String filename = "roomMap.dat";
	User nullUser=null;
	public Room foyer=new Room("Foyer",null,0,nullUser);
	public Server serverObject;
	
	/**
	 * 
	 */
	public RoomManager(Server serverObject) {
		this.serverObject=serverObject;
		loadRoomMap();
		removeAllUsers(foyer);
		if(serverObject.ui instanceof GraphicalUI){
			((GraphicalUI)serverObject.ui).updateRoomTree();
		}
	}

	/**
	 * loads the roommap
	 * @return true if successful and false otherwise
	 */
	public boolean loadRoomMap() {
		// load existing users from database
		File file = new File(filename);
		
		if (file.exists()) {
			try {
				FileInputStream f = new FileInputStream(file);
				ObjectInputStream s = new ObjectInputStream(f);
				Object inputObject = s.readObject();
				
				if (inputObject instanceof Room)
					this.foyer = (Room) inputObject;
				
				s.close();
				//removeAllUsers(foyer);
				//TODO: null weg
				return true;
			} catch (IOException e) {
				e.printStackTrace();
				return false;
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
				return false;
			}
		} else {
			//serverObject.ui.postError("Failed to load room map.");
			return false;
		}
		
	}
	
	/**
	 * saves roommap
	 * @return true if successful and false otherwise
	 */
	public boolean saveRoomMap() {
		File file = new File(filename);
		FileOutputStream f;
		ObjectOutputStream s;
		
		try {
			f = new FileOutputStream(file);
			s = new ObjectOutputStream(f);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		
		try {
			s.writeObject(this.foyer);
			s.close();
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		if(serverObject.ui instanceof GraphicalUI){
			((GraphicalUI)serverObject.ui).updateRoomTree();
		//	SysMessage newUserMessage = new SysMessage(CATEGORY.ROOMMANAGEMENT, MESSAGE.SEND_ROOM_LIST,"SERVER", this.foyer);
			//serverObject.networkListener.distributeMsg(newUserMessage);
			
		}
		SysMessage newUserMessage = new SysMessage(CATEGORY.ROOMMANAGEMENT, MESSAGE.SEND_ROOM_LIST,"SERVER", this.foyer.copyRoom());
		if(serverObject.networkListener!=null){
		serverObject.networkListener.distributeMsg(newUserMessage);
		}
		return true;
	}
	
	/**
	 * moves an user to an other room
	 * @param user		user to be moved
	 * @param dest		destination of the user
	 * @return 0 if successful 
	 * @return 1 destination didn't exist
	 * @return 2 user didn't exist
	 * @return 3 user is blacklisted
	 * @return 4 user not on whitelist
	 * @return 5 user needs mod rights
	 * @return 6 user needs admin rights
	 * @return 7 unkown error
	 */
	public int moveUserTo(User user,List<String> dest){
	
		Room destRoom=this.getRoom(dest);
		Room originRoom=this.getRoom(user.dir);
		if ((originRoom!=null)&&(originRoom.userExists(user.name))){
			if(destRoom!=null){
				
				switch(destRoom.userentry(user)){
				case 0:
					serverObject.userManager.users.get(user.name).dir=dest;
					originRoom.userExit(user.name);
					user.dir=dest;
					//destRoom.addChild(originRoom.getChild(user.name));
					if(serverObject.ui instanceof GraphicalUI){
						((GraphicalUI)serverObject.ui).updateRoomTree();
					}
					return 0;
			
				case 1:
					return 3;
					
				case 2:
					return 4;
					
				case 3:
					return 5;
					
				case 4:
					return 6;
					
				case 5:
					return 7;
					default:
						return 7;
				}
				
			
			
			}else{
				return 1;
			}
		}else{
			return 2;
		}
	}

	/**
	 * creates a new room
	 * @param dir contains the directory pointing to the room last element is the name of the new room
	 * @return false if error occurred and true if successful
	 */
	public boolean createRoom(List<String> dir,User Owner) {
		Room temp;
		List<String> tempdir=new ArrayList<String>();
		for(int i=0;i<dir.size()-1;i++){
			tempdir.add(dir.get(i));
		}
		temp = getRoom(tempdir);
		if (temp != null) {

			if (((dir.size()>0)&&!temp.childExists(dir.get(dir.size()-1)))&&temp.getOwner()==null) {
				temp.createChild(dir.get(dir.size()-1),Owner);
				this.saveRoomMap();
				return true;
			} else {
				this.saveRoomMap();
				return true;				//WTF!
			}
		} else {
			return false;
		}
		
	}
	/**
	 * return the reference to a room
	 * @param dir directory of the room to be returned
	 * @return reference of the room
	 */
	public Room getRoom(List<String> dir){
		Room temp;
		temp=this.foyer;
		if((dir!=null)&&(dir.size()>1)){
		for(int i=1; i<dir.size();i++){
			if(temp.childExists(dir.get(i))){
				temp=(Room)temp.getChild(dir.get(i));
			}else{
				return null;
			}
		}
		}
		return temp;
	
	}
	/**
	 * removes an room and all childrooms
	 * moves all users to parent room
	 * @param dir directory of the room to be removed
	 * @return
	 */
	//TODO error handling
	public int removeRoom(List<String> dir){
		Room parent=(Room)(getRoom(dir).getParent());
		Room child=getRoom(dir);
		if (parent==null) return 1;
		if (!parent.childExists(dir.get(dir.size()-1))) return 2;
		if(child.getChildren()!=null){
		for(int i=0;i<child.getChildren().size();i++){
			if((child.getChildAt(i) instanceof Room)&&(!child.getChildren().get(i).isEmpty())){
				this.removeRoom(((Room)child.getChild(child.getChildren().get(i))).getDir());
			}
		}
		}
		for(String name : child.userKeySet()){
			parent.userentry(child.getUser(name));
			child.getUser(name).dir=parent.getDir();
			serverObject.userManager.users.get(name).dir=parent.getDir();
			child.userExit(name);
		}
		parent.deleteChild(dir.get(dir.size()-1));
		this.saveRoomMap();
		return 0;
	}
	
	public void removeAllUsers(Room temp){
		//Room temp=getRoom(dir);
		if(temp!=null){
			temp.clearUserlist();
		
		for(int i=0;i<temp.getChildCount();i++){
			if(temp.getChild(temp.getChildren().get(i)) instanceof Room){
			removeAllUsers(((Room)temp.getChild(temp.getChildren().get(i))));
			}
		}
		}
	}
	
	/**
	 * changes the name of an room
	 * @param dir List of string the first part is the directory to the room which name should be changed the last element in the list is the new name of the room
	 * @return true
	 */
	public boolean changeRoomName(List<String> dir){
		List<String> tempDir=new ArrayList<String>();
		for(int i=0;i<dir.size()-1;i++){
			tempDir.add(dir.get(i));
		}
		String newName=dir.get(dir.size()-1);
		getRoom(tempDir).changeName(newName);
		saveRoomMap();
		return true;
	}
	
	/**
	 * sets the dir of users to the correct room
	 * @param dir directory to the room to check
	 */
	public void refreshUserDir(List<String> dir){
		Room tempRoom=getRoom(dir);
		for(int i=0;i<tempRoom.getChildCount();i++){
			if(tempRoom.getChildAt(i) instanceof Room){
				tempRoom.directory=null;
				tempRoom.directory=((Room)tempRoom.getParent()).directory;
				tempRoom.directory.add(tempRoom.toString());
				refreshUserDir(((Room)tempRoom.getChildAt(i)).getDir());
			}else if(tempRoom.getChildAt(i) instanceof Room){
				serverObject.userManager.users.get(tempRoom.getChildAt(i).toString()).dir=dir;
			}
		}
	}
	
	public void moveRoom(List<String>dir, List<String>newDir){
		Room oldRoom=getRoom(dir);
		List<String> newtempDir=new ArrayList<String>();
		for(int i=0;i<newDir.size()-1;i++){
			newtempDir.add(newDir.get(i));
		}
		((Room)getRoom(newtempDir)).addChild(oldRoom);
	
	List<String> oldtempDir=new ArrayList<String>();
	for(int i=0;i<dir.size()-1;i++){
		oldtempDir.add(dir.get(i));
	}
	((Room)getRoom(oldtempDir)).deleteChild(oldRoom.toString());
	newtempDir.add(oldRoom.toString());
	((Room)((Room)getRoom(newtempDir)).getChild(oldRoom.toString())).directory=newtempDir;
	refreshUserDir(newtempDir);
	saveRoomMap();
	}
	}

